
package com.idealighter.game.games.weishuwu.struct;

import com.google.common.collect.EvictingQueue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.weishuwu.util.CardsTypeGetter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;

/**
 * .. 魏蜀吴桌子.
 * 
 * @date 2016年2月17日 上午10:46:55
 */
public class WeishuwuTable extends AbstractTable {

  // 座位数量
  private static final int SEAT_NUM = 100;
  private static final int SYS_SEAT_NUM = 5;
  public static final int MAX_BANKER_SIZE = 3;
  public static final int HISTORY_SIZE = 20;

  // 1个庄家和4个虚拟闲家
  public static final int BANKER_SEAT = -5;
  public static final int PLAYER_SEAT1 = -2;
  public static final int PLAYER_SEAT2 = -3;
  public static final int PLAYER_SEAT3 = -4;
  public static final int PLAYER_SEAT4 = -5;
  private static final int CARD_NUM = 3;
  private static final int BASE_NUM = 2;

  public final WeishuwuRoom room;
  // 房间里面的桌子
  public final List<WeishuwuSeat> seats;
  // 庄家和4个闲家
  public final List<WeishuwuSeat> sysSeats;
  // 桌子是否准备完成
  public boolean readied = false;
  // 桌上的总筹码
  public long totalChips = 0;

  // 当前庄家Id，系统坐庄为0
  public long bankerId = 0;
  // 玩家总下注信息
  public Map<Integer, Long> tableBets = Maps.newConcurrentMap();
  // 一副牌
  public final List<WeishuwuCard> cards;
  // 当前状态
  public GameStatus status = GameStatus.REST;
  // 队列庄家
  public EvictingQueue<Long> applyBankers = EvictingQueue.create(MAX_BANKER_SIZE);

  // 路单记录
  public final EvictingQueue<Integer> history = EvictingQueue.create(HISTORY_SIZE);
  // 输赢记录
  public final EvictingQueue<Integer> win = EvictingQueue.create(HISTORY_SIZE);

  // 虎将记录
  public final EvictingQueue<Integer> hero = EvictingQueue.create(HISTORY_SIZE);

  public final double[] cbMultiple = { 12, 12, 2, 9, 2, 3, 1.53, 2.45, 3 };
  // 开出结果
  public List<BettingDecision> result = Lists.newArrayList();
  // 吴家牌
  public List<WeishuwuCard> banker = Lists.newArrayList();
  // 蜀家牌
  public List<WeishuwuCard> normalPlayer = Lists.newArrayList();

  // 游戏步骤(休息、下注、开奖、结算)定时Future
  public ScheduledFuture<?> stepFuture = null;

  public long tempGold = 0;

  // 系统收益
  public long earn = 0;
  public int cardIndex = 0;

  /**
   * 构造函数 .
   * 
   * @param id .
   * @param room .
   */
  public WeishuwuTable(int id, WeishuwuRoom room) {
    super(id);
    this.room = room;
    this.seats = createSeats();
    this.sysSeats = createSysSeat();
    this.cards = createCards();
  }

  private List<WeishuwuCard> createCards() {
    List<WeishuwuCard> cards = Lists.newArrayList();
    for (int i = 0; i < CARD_NUM; i++) {
      cards.addAll(Arrays.asList(WeishuwuCard.values()));
    }
    Collections.shuffle(cards);
    return cards;
  }

  /**
   * 创建位置.
   * 
   * @return
   */
  private List<WeishuwuSeat> createSeats() {
    List<WeishuwuSeat> seats = new ArrayList<>(SEAT_NUM);
    for (int i = 0; i < SEAT_NUM; i++) {
      seats.add(new WeishuwuSeat(i, this));
    }

    return Collections.unmodifiableList(seats);

  }

  /**
   * 创建系统位置 .
   * 
   * @return
   */
  private List<WeishuwuSeat> createSysSeat() {
    List<WeishuwuSeat> seatList = new ArrayList<>(SYS_SEAT_NUM);
    for (int i = 1; i <= SYS_SEAT_NUM; i++) {
      WeishuwuSeat sysSeat = new WeishuwuSeat(-i, this);
      if (i == -BANKER_SEAT) {
        sysSeat.setPlayerName("系统坐庄");
      } else {
        sysSeat.setPlayerName("闲家" + (i));
      }
      sysSeat.setPlayerId(0);
      seatList.add(sysSeat);
    }
    return seatList;
  }

  /**
   * 推断结果.
   * 
   * 
   */
  public void deduceWinner() {
    WeishuwuSeat seat = banker();
    int pointBanker = CardsTypeGetter.getCardPoint(banker);
    int pointnormalPlayer = CardsTypeGetter.getCardPoint(normalPlayer);
    boolean hasHero = false;
    if (pointBanker > pointnormalPlayer) {
      result.add(BettingDecision.WU);
      if (pointBanker >= 8) {
        result.add(BettingDecision.WU_DU_DU);
        hero.add(Hero.WU_DU_DU.val);
        hasHero = true;
      }
      seat.bankerWin++;
    } else if (pointBanker < pointnormalPlayer) {
      result.add(BettingDecision.SHU);
      if (pointnormalPlayer >= 8) {
        result.add(BettingDecision.SHU_HU_JIANG);
        hero.add(Hero.SHU_HU_IANG.val);
        hasHero = true;
      }
      seat.playerWin++;
    } else if (pointBanker == pointnormalPlayer) {
      result.add(BettingDecision.WEI);
      seat.tie++;
    }
    if (banker.size() + normalPlayer.size() == BASE_NUM * 2) {
      result.add(BettingDecision.XIAO_MA);
    } else if (banker.size() + normalPlayer.size() > BASE_NUM * 2) {
      result.add(BettingDecision.DA_NIU);
    }

    if (CardsTypeGetter.getCardsType(banker.subList(0, 2)) == WeishuwuCardsType.PAIR) {
      result.add(BettingDecision.WU_PAIRE);
      seat.bankerPaire++;
    }
    if (CardsTypeGetter.getCardsType(normalPlayer.subList(0, 2)) == WeishuwuCardsType.PAIR) {
      result.add(BettingDecision.SHU_PAIRE);
      seat.playerPaire++;
    }
    if (!hasHero) {
      hero.add(Hero.NONE.val);
    }
    seat.score++;
  }

  /**
   * 结算.
   * 
   * 
   */
  public void balance() {
    WeishuwuSeat banker = banker();
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() > 0 && seat.getPlayerId() != banker.getPlayerId()) {
        for (BettingDecision betType : result) {
          long chips = seat.bets.getOrDefault(betType.type, 0L);
          double muti = cbMultiple[betType.type];
          seat.billChips += chips * (muti);
        }
        banker.billChips += seat.totalBets() - seat.billChips;
        // seat.billChips -= seat.totalBets();
      }
    }
    earn = banker.getPlayerId() > 0 ? -banker.billChips : playerTotalBets() - playerBill();
  }

  /**
   * 输赢的历史记录.
   */
  public void addHistory() {
    addScoreRecord();
    addWinRecord();

  }

  /**
   * 输赢记录.
   * 
   * 
   */
  private void addWinRecord() {
    for (BettingDecision bty : result) {
      if (bty == BettingDecision.SHU) {
        win.add(bty.type);
        break;
      } else if (bty == BettingDecision.WU) {
        win.add(bty.type);
        break;
      } else if (bty == BettingDecision.WEI) {
        win.add(bty.type);
        break;
      }
    }
  }

  /**
   * 路单记录.
   * 
   * 
   */
  public void addScoreRecord() {
    boolean bankWin = false; // 蜀
    boolean bankPaire = false;
    boolean playerPaire = false;// 吴
    boolean playerWin = false;
    ScoreRecord scoreRecord = null;
    for (BettingDecision bty : result) {
      if (bty == BettingDecision.SHU) {
        bankWin = true;
      } else if (bty == BettingDecision.WU) {
        playerWin = true;
      } else if (bty == BettingDecision.WEI) {
        bankWin = false;
        playerWin = false;
      }
      if (bty == BettingDecision.SHU_PAIRE) {
        bankPaire = true;
      }
      if (bty == BettingDecision.WU_PAIRE) {
        playerPaire = true;
      }
    }
    if (bankWin && !playerWin && !bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.SHU_NORMAL;
    } else if (bankWin && !playerWin && !bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.SHU_WU_PAIRE;
    } else if (bankWin && !playerWin && bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.SHU_PAIRE;
    } else if (bankWin && !playerWin && bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.SHU_PAIRE_WU_PAIRE;
    } else if (!bankWin && !playerWin && !bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.WEI;
    } else if (!bankWin && !playerWin && bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.WEI_SHU_PAIRE;
    } else if (!bankWin && !playerWin && !bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.WEI_SHU_PAIRE;
    } else if (!bankWin && !playerWin && bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.WEI_SHU_PAIRE_WU_PAIRE;
    } else if (!bankWin && playerWin && !bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.WU_NORMAL;
    } else if (!bankWin && playerWin && bankPaire && !playerPaire) {
      scoreRecord = ScoreRecord.WU_SHU_PAIRE;
    } else if (!bankWin && playerWin && !bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.WU_PAIRE;
    } else if (!bankWin && playerWin && bankPaire && playerPaire) {
      scoreRecord = ScoreRecord.WU_PAIRE_SHU_PAIRE;
    }
    history.add(scoreRecord.type);
  }

  /**
   * 限制下注筹码 .
   * 
   * 
   * @return
   */
  public long limitChips(int area) {
    long chips = tableBets.getOrDefault(BettingDecision.SHU_PAIRE.type, 0L)
        + tableBets.getOrDefault(BettingDecision.WU_PAIRE.type, 0L);
    chips += Math.max(tableBets.getOrDefault(BettingDecision.DA_NIU.type, 0L),
        tableBets.getOrDefault(BettingDecision.XIAO_MA.type, 0L));
    switch (area) {
      case 0:
        chips += tableBets.getOrDefault(BettingDecision.WU.type, 0L)
            + tableBets.getOrDefault(BettingDecision.WU_DU_DU.type, 0L);
        break;
      case 1:
        chips += tableBets.getOrDefault(BettingDecision.SHU.type, 0L)
            + tableBets.getOrDefault(BettingDecision.SHU_HU_JIANG.type, 0L);
        break;
      case 2:
        chips += tableBets.getOrDefault(BettingDecision.WEI.type, 0L);
        break;
      default:
        chips += Math.max(
            Math.max(tableBets.getOrDefault(BettingDecision.WU.type, 0L),
                tableBets.getOrDefault(BettingDecision.SHU.type, 0L)),
            tableBets.getOrDefault(BettingDecision.WEI.type, 0L));
        break;
    }
    return chips;
  }

  /**
   * 机器人收益 .
   * 
   * @return
   */
  public long robotBill() {
    long bill = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      if (seat.isRobot()) {
        bill += seat.billChips;
      }
    }
    return bill;
  }

  /**
   * 真实玩家收益 .
   * 
   * @return
   */
  public long playerBill() {
    long bill = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      if (!seat.isRobot()) {
        bill += seat.billChips;
      }
    }
    return bill;
  }

  /**
   * 桌子玩家下注 .
   * 
   * @return
   */
  public Map<Integer, Long> tableBets() {
    Map<Integer, Long> tableBets = new HashMap<>();
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      for (Entry<Integer, Long> seatBetEtr : seat.bets.entrySet()) {
        int area = seatBetEtr.getKey();
        long areaBet = tableBets.getOrDefault(area, 0L);
        tableBets.put(area, areaBet + seatBetEtr.getValue());
      }
    }

    return tableBets;
  }

  /**
   * 玩家合计总下注 .
   * 
   * @return
   */
  public long playerTotalBets() {
    long playerTotalBets = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      for (Entry<Integer, Long> seatBetEtr : seat.bets.entrySet()) {
        if (!seat.isRobot()) {
          playerTotalBets += seatBetEtr.getValue();
        }
      }
    }

    return playerTotalBets;
  }

  /**
   * 玩家某个区域合计总下注 .
   * 
   * @param area .
   * @return
   */
  public Long playerareaBets(int area) {
    long playerareaBets = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      for (Entry<Integer, Long> seatBetEtr : seat.bets.entrySet()) {
        if (!seat.isRobot() && seatBetEtr.getKey() == area) {
          playerareaBets += seatBetEtr.getValue();
        }
      }
    }

    return playerareaBets;
  }

  /**
   * 机器人合计总下注 .
   * 
   * @return
   */
  public long robotTotalBets() {
    long robotTotalBets = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      for (Entry<Integer, Long> seatBetEtr : seat.bets.entrySet()) {
        if (seat.isRobot()) {
          robotTotalBets += seatBetEtr.getValue();
        }
      }
    }

    return robotTotalBets;
  }

  /**
   * 机器人某个区域合计总下注 .
   * 
   * @param area .
   * @return
   */
  public Long robotareaBets(int area) {
    long robotareaBets = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      for (Entry<Integer, Long> seatBetEtr : seat.bets.entrySet()) {
        if (seat.isRobot() && seatBetEtr.getKey() == area) {
          robotareaBets += seatBetEtr.getValue();
        }
      }
    }

    return robotareaBets;
  }

  /**
   * 桌子区域押注 .
   * 
   * @param area .
   * @return
   */
  public long bet(int area) {
    long areaBet = 0;
    for (WeishuwuSeat seat : seats) {
      if (seat.getPlayerId() == 0) {
        continue;
      }
      areaBet += seat.bets.getOrDefault(area, 0L);
    }

    return areaBet;
  }

  /**
   * 重置桌子.
   */
  public void reset() {
    this.readied = false;
    this.earn = 0;
    this.totalChips = 0;
    this.tempGold = 0;
    this.tableBets.clear();
    this.cardIndex = 0;
    banker.clear();
    normalPlayer.clear();
    result.clear();
    Collections.shuffle(cards);
    Collections.shuffle(cards);
  }

  /**
   * 闲家合计筹码 .
   * 
   * @return
   */
  public long playesChips() {
    long playesChips = 0;
    for (WeishuwuSeat s : seats) {
      if (!s.dealer && s.getPlayerId() > 0) {
        playesChips += s.getTotalChips();
      }
    }

    return playesChips;
  }

  /**
   * 获取seat .
   * 
   * @param order .
   * @return
   */
  public WeishuwuSeat getSeat(int order) {

    return seats.get(order);
  }

  @SuppressWarnings("unchecked")
  @Override
  public WeishuwuRoom room() {
    return room;
  }

  @Override
  public List<WeishuwuSeat> seats() {

    return seats;
  }

  /**
   * 庄家 .
   * 
   * @return
   */
  public WeishuwuSeat banker() {
    if (bankerId == 0) {
      return dealer();
    } else {
      for (WeishuwuSeat seat : seats) {
        if (seat.getPlayerId() == bankerId) {
          return seat;
        }
      }
    }
    return dealer();
  }

  /**
   * 庄家 .
   * 
   * @return
   */
  public WeishuwuSeat dealer() {

    for (WeishuwuSeat seat : sysSeats) {
      if (seat.getOrder() == BANKER_SEAT) {
        return seat;
      }
    }
    return null;
  }

}
